package com.hk.core.autoconfigure.springdoc;

import com.hk.core.springdoc.openapi.JavaDocOpenAPIService;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.providers.SpringDocJavadocProvider;
import org.springdoc.core.service.OpenAPIService;
import org.springdoc.core.service.SecurityService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.*;


/**
 * springdoc-opanapi 根据java 注释 生成文档，可以不使用 swagger的注解。
 * 使用  {@link  SpringDocJavadocProvider} 获取注释，需要引入  therapi-runtime-javadoc-scribe 和 therapi-runtime-javadoc
 * </p>
 * 支持根据接口导入到 Apifox，接口地址默认为 /v3/v3/api-docs,配置参考: springdoc.api-docs.path
 * </p>
 * web ui界面访问地址默认为: /swagger-ui/index.html, 配置参考: springdoc.swagger-ui.path
 */
@AutoConfiguration
@RequiredArgsConstructor
@ConditionalOnClass(JavaDocOpenAPIService.class)
@ConditionalOnProperty(prefix = SpringDocProperties.DOC_PREFIX, name = "enabled", havingValue = "true")
@EnableConfigurationProperties(value = {SpringDocProperties.class})
public class SpringDocAutoConfiguration {

    private final SpringDocProperties springDocProperties;

    @Bean
    public OpenAPI openAPI() {
        OpenAPI openApi = new OpenAPI();
        // 文档基本信息
        SpringDocProperties.InfoProperties infoProperties = springDocProperties.getInfo();
        Info info = convertInfo(infoProperties);
        openApi.info(info);
        // 扩展文档信息
        openApi.externalDocs(springDocProperties.getExternalDocs());
        openApi.tags(springDocProperties.getTags());
        openApi.paths(springDocProperties.getPaths());
        Components components = springDocProperties.getComponents();
        openApi.components(components);
        if (Objects.nonNull(components)) {
            Map<String, SecurityScheme> securitySchemes = components.getSecuritySchemes();
            if (Objects.nonNull(securitySchemes)) {
                Set<String> keySet = securitySchemes.keySet();
                List<SecurityRequirement> list = new ArrayList<>(keySet.size());
                SecurityRequirement securityRequirement = new SecurityRequirement();
                keySet.forEach(securityRequirement::addList);
                list.add(securityRequirement);
                openApi.security(list);
            }
        }
        return openApi;
    }

    private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
        Info info = new Info();
        info.setTitle(infoProperties.getTitle());
        info.setDescription(infoProperties.getDescription());
        info.setContact(infoProperties.getContact());
        info.setLicense(infoProperties.getLicense());
        info.setVersion(infoProperties.getVersion());
        return info;
    }

    @Bean
    public OpenAPIService openAPIService(SecurityService securityParser,
                                         SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
                                         ObjectProvider<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
                                         ObjectProvider<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
                                         ObjectProvider<JavadocProvider> javadocProvider) {
        return new JavaDocOpenAPIService(openAPI(), securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers.getIfAvailable(),
                serverBaseUrlCustomizers.getIfAvailable(), javadocProvider.getIfAvailable());
    }
}
